home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
win
/
rtfhelp.zip
/
RTFHPARS.C
< prev
next >
Wrap
Text File
|
1994-11-06
|
17KB
|
507 lines
/*
======================================================================
RTFHelp Windows Help Generation Tool
(C) Copyright 1994 by J. Hlavaty
RTFHPars.c
This routine parses the lines of the HDC file
======================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rtfhelp.h"
int Tokenize( FILE *flInput, FILE *flOutput, char *pLine )
{
char *ptrTokenStart, *ptrTokenNext, *ptrStartOfLine ;
char *ptrTmp ;
int lenCmd, i ;
int idCmd, rc ;
char strCmd[45], *strHasCRLF ;
BOOL bNoSpace = FALSE ;
struct COMMANDENTRY *pCommandTable = &CommandList[0] ;
static char *WhiteSpace = " " ;
// certain languages (such as Finnish) can have long words so give
// plenty of room
static char strTagHeader[255] ;
static char strTagTrailer[255] ;
static int multipass = FALSE ;
// get line of text passed in...
ptrStartOfLine = pLine ;
// if text is a non-ANSI code page (currently only 850 is supported)
// then convert to ANSI
if (codepage)
TranslateCPToANSI( codepage, ptrStartOfLine ) ;
// reset pointer to text passed in...
ptrTokenStart = pLine ;
// NOTE: first call to strtok() will strip off leading delimiters...
if ( NULL == ( ptrTokenNext = strtok( ptrStartOfLine, WhiteSpace ) ) )
return INTERNAL_ERROR ;
// skip any leading spaces...
ptrStartOfLine = ptrTokenNext ;
// validate that the length of the line (without initial spaces)
// is within the bounds of our buffer (including null terminator)
lenCmd = strlen(ptrTokenNext) ;
if ( ( lenCmd + 1 ) > sizeof ( strCmd ) )
{
return INTERNAL_ERROR ;
}
// copy parsed command, if any (we won't know until we check against our
// table of commands). This first command may in fact be just raw text
strcpy( strCmd, ptrTokenNext ) ;
// does our command string have a CRLF (newline)? It can if it's the
// only thing on a line (i.e., the tag has no arguments)
if ( strHasCRLF = strstr( strCmd, "\n" ) )
{
*strHasCRLF = '\0' ; // remove newline
lenCmd-- ; // subtract newline from command length count...
}
// ignore a blank line (the newline converted to a NULLCHAR above)
if ('\0' == strCmd[0])
{
return RC_OK ;
}
// move ptr to next potential token...
ptrTokenNext += lenCmd ;
// step over NULLCHAR strtok() inserted...
ptrTokenNext++ ;
// ptrTokenNext now points at a command's args
// ignore leading spaces...
while ( ' ' == *ptrTokenNext )
ptrTokenNext++ ;
bNoSpace = FALSE ;
// assume that our line is plaintext (raw text), unless we know otherwise
idCmd = plaintext ;
// notice that all of the following (within #if 0/#else) can be replaced
// with just a few short lines of code. Readability is greatly reduced,
// however. Use whichever you prefer (the collection of ifs can sometimes
// be easier to debug if you're changing the parser)
#if 0 // 0 = use for loop, 1 = use ifs
i ; // get rid of unused local variable msg
if ('*' == pLine[0]) // comment chars must be first character on a line
idCmd = comment ;
if (';' == pLine[0])
idCmd = comment ;
if (!strcmp(strCmd,"BOLD"))
idCmd = bold ;
if (!strcmp(strCmd,"BUILD"))
idCmd = build ;
if (!strcmp(strCmd,"CONTEXTID"))
idCmd = contextID ;
if (!strcmp(strCmd,"TITLE"))
idCmd = title ;
if (!strcmp(strCmd,"KEYWORD"))
idCmd = keyword ;
if (!strcmp(strCmd,"BROWSESEQ"))
idCmd = browseseq ;
if (!strcmp(strCmd,"XREF"))
idCmd = putlink ;
if (!strcmp(strCmd,"PUTLINK"))
idCmd = putlink ;
if (!strcmp(strCmd,"DEFINITION"))
idCmd = putpopup ;
if (!strcmp(strCmd,"PUTPOPUP"))
idCmd = putpopup ;
if (!strcmp(strCmd,"XREFID"))
idCmd = xrefID ;
if (!strcmp(strCmd,"XREFCONTEXT"))
idCmd = definepopup ;
if (!strcmp(strCmd,"DEFINEPOPUP")) // for definitions
idCmd = definepopup ;
if (!strcmp(strCmd,"LINKCONTEXT"))
idCmd = definelink ;
if (!strcmp(strCmd,"DEFINELINK"))
idCmd = definelink ;
if (!strcmp(strCmd,"PAGE"))
idCmd = newpage ;
if (!strcmp(strCmd,"PARA"))
idCmd = newparagraph ;
if (!strcmp(strCmd,"DEFFONT"))
idCmd = deffont ;
if (!strcmp(strCmd,"FONTSIZE"))
idCmd = fontsize ;
if (!strcmp(strCmd,"FONT"))
idCmd = font ;
if (!strcmp(strCmd,"LEFT"))
idCmd = leftalign ;
if (!strcmp(strCmd,"CENTER"))
idCmd = centeralign ;
if (!strcmp(strCmd,"RIGHT"))
idCmd = rightalign ;
if (!strcmp(strCmd,"JUST"))
idCmd = justified ;
if (!strcmp(strCmd,"MARGL"))
idCmd = marginleft ;
if (!strcmp(strCmd,"MARGR"))
idCmd = marginright ;
if (!strcmp(strCmd,"MARGT"))
idCmd = margintop ;
if (!strcmp(strCmd,"MARGB"))
idCmd = marginbottom ;
if (!strcmp(strCmd,"DEFTAB"))
idCmd = deftab ;
if (!strcmp(strCmd,"TX"))
idCmd = tabpos ;
if (!strcmp(strCmd,"TQR"))
idCmd = tabright ;
if (!strcmp(strCmd,"TQC"))
idCmd = tabcenter ;
if (!strcmp(strCmd,"TQDEC"))
idCmd = tabdec ;
if (!strcmp(strCmd,"TB"))
idCmd = tabbar ;
if (!strcmp(strCmd,"SA"))
idCmd = spaceafter ;
if (!strcmp(strCmd,"SB"))
idCmd = spacebefore ;
if (!strcmp(strCmd,"SL"))
idCmd = spacebetween ;
if (!strcmp(strCmd,"FIRSTINDENT"))
idCmd = firstlineindent ;
if (!strcmp(strCmd,"LEFTINDENT"))
idCmd = leftindent ;
if (!strcmp(strCmd,"RIGHTINDENT"))
idCmd = rightindent ;
if (!strcmp(strCmd,"LINE"))
idCmd = requiredlinebreak ;
if (!strcmp(strCmd,"TAB"))
idCmd = tab ;
if (!strcmp(strCmd,"DEFFORMAT"))
idCmd = defformat ;
if (!strcmp(strCmd,"BMC"))
idCmd = bitmapcharacter ;
if (!strcmp(strCmd,"BOX"))
idCmd = box ;
if (!strcmp(strCmd,"PARD"))
idCmd = pard ;
if (!strcmp(strCmd,"FOREGROUNDCOLOR"))
idCmd = foregroundcolor ;
if (!strcmp(strCmd,"PLAIN"))
idCmd = plain ;
if (!strcmp(strCmd,"ITALIC"))
idCmd = italic ;
if (!strcmp(strCmd,"SMALLCAPS"))
idCmd = smallcaps ;
if (!strcmp(strCmd,"SPACECHAR"))
idCmd = spacechar ;
if (!strcmp(strCmd,"KEEP"))
idCmd = keep ;
if (!strcmp(strCmd,"KEEPNEXT"))
idCmd = keepnext ;
#else
if ( ('*' == pLine[0]) || // comment chars must be
(';' == pLine[0]) ) // first character on a line
{
idCmd = comment ; // no need to check table
}
else // this way shrinks the executable by more than 1K!
{ // for all commands in the table...
for (i=0; i < NOOFCMDS ; i++)
{ // is our command string the same as the string in this entry
// of the command table (note that case is preserved during the test)
if ( !strcmp( strCmd, pCommandTable[i].strCmd ) )
{
// yes, we found our command
idCmd = pCommandTable[i].idCmd ; // OK, remember ID
if ( comment == idCmd )
{
// in case the user put spaces before a * or ; we must
// make sure that such a situation is not caught here
// as a comment. It is plain text as a comment character
// MUST begin on column 1. Another option would have
// been to update the table to put comments as id plaintext
// as they are caught outside the 'for' loop in any case...
idCmd = plaintext ;
}
break ; // and stop checking...
}
}
}
#endif
// clear out any previous header or trailer text
strTagHeader[0] = '\0' ;
strTagTrailer[0] = '\0' ;
if ( (idCmd != plaintext) &&
(idCmd != comment) &&
(TRUE == bVerbose) )
{ // only inform user about tags (except comments), not raw text
printf( "Processing %s...\n", strCmd ) ;
}
switch(idCmd) {
case build: // build tag*
strcpy(strTagHeader,"*{\\footnote ") ;
strcpy(strTagTrailer, "}") ;
break ;
case title: // topic title*
strcpy(strTagHeader,"${\\footnote ") ;
strcpy(strTagTrailer, "}") ;
break;
case keyword: // keyword*
strcpy(strTagHeader,"K{\\footnote ") ;
strcpy(strTagTrailer, "}") ;
break ;
case browseseq: // browse sequence identifier*
strcpy(strTagHeader,"+{\\footnote ") ;
strcpy(strTagTrailer, "}") ;
break;
case putlink: // hot spot -- links another topic*
strcpy(strTagHeader,"{\\uldb") ;
strcpy(strTagTrailer, "}") ;
break ;
case putpopup: // link to a popup topic*
strcpy(strTagHeader,"{\\ul") ; // space is removed in new version
strcpy(strTagTrailer, "}") ; // but notice we DO have one before the tag
break ; // so it won't be underlined
case xrefID: // creates a link to topic w. context string*
strcpy(strTagHeader,"{\\v") ; // remove extra space (user must add space bet. keyword and arg)
strcpy(strTagTrailer, "}") ;
break ;
case definepopup: // specifies a context string ( = definelink)*
strcpy(strTagHeader,"\\page #{\\footnote ") ;
strcpy(strTagTrailer, "}") ;
break;
case definelink: // specifies a context string ( = definepopup)*
strcpy(strTagHeader,"#{\\footnote ") ;
strcpy(strTagTrailer, "}") ;
break;
case bold: // starts bold text*
strcpy(strTagHeader,"{\\b") ; // remove space
strcpy(strTagTrailer, "}") ;
break ;
case comment:
return RC_OK ; // ignore this line, it's a comment
break;
case newpage: // marks the end of a topic*
strcpy(strTagHeader,"\\page") ;
*ptrStartOfLine = '\0' ; // zero out text
ptrTokenNext = ptrStartOfLine ;
bNoSpace = TRUE ;
break ;
case newparagraph: // marks end of a paragraph*
strcpy(strTagHeader,"\\par") ;
*ptrStartOfLine = '\0' ; // zero out text
ptrTokenNext = ptrStartOfLine ;
bNoSpace = TRUE ;
break ;
case leftalign:
case centeralign:
case rightalign:
case justified:
// aligns text along left/center/right indent
// or justified*
if (leftalign == idCmd)
strcpy(strTagHeader,"\\par\\ql") ;
if (centeralign == idCmd)
strcpy(strTagHeader,"\\par\\qc") ;
if (rightalign == idCmd)
strcpy(strTagHeader,"\\par\\qr") ;
if (justified == idCmd)
strcpy(strTagHeader,"\\par\\qj") ;
*ptrStartOfLine = '\0' ; // zero out text
ptrTokenNext = ptrStartOfLine ;
bNoSpace = TRUE ;
break ;
case deffont: // sets default font number (from font table)*
strcpy(strTagHeader,"\\deff") ; // note: no space after 'deff'
bNoSpace = TRUE ;
break ;
case fontsize: // sets the size of the font*
strcpy(strTagHeader,"\\fs") ; // note there is no space after 'fs'
bNoSpace = TRUE ;
break ;
case font: // sets the font number (from font table)*
strcpy(strTagHeader,"\\f") ; // note there is no space after 'f'
bNoSpace = TRUE ;
break ;
/*
* case marginleft:
* strcpy(strTagHeader,"\\margl") ;
* bNoSpace = TRUE ;
* break ;
* case marginright:
* strcpy(strTagHeader,"\\margr") ;
* bNoSpace = TRUE ;
* break;
* case margintop:
* strcpy(strTagHeader,"\\margt") ;
* bNoSpace = TRUE ;
* break;
* case marginbottom:
* strcpy(strTagHeader,"\\margb") ;
* bNoSpace = TRUE ;
* break;
*/
case deftab:
strcpy(strTagHeader,"\\deftab") ;
bNoSpace = TRUE ;
break;
case tabpos: // sets position of a tab stop*
strcpy(strTagHeader,"\\tx") ;
bNoSpace = TRUE ;
break;
case tabright: // advances to next tab stop, aligns text right*
strcpy(strTagHeader,"\\tqr") ;
bNoSpace = TRUE ;
break;
case tabcenter: // advances to next tab stop, centers text*
strcpy(strTagHeader,"\\tqc") ;
bNoSpace = TRUE ;
break;
case tabdec:
strcpy(strTagHeader,"\\tqdec") ;
bNoSpace = TRUE ;
break;
case tabbar: // advances to next tab stop*
strcpy(strTagHeader,"\\tb") ;
bNoSpace = TRUE ;
break;
case spaceafter: // sets amount of vertical spacing after paragraph*
strcpy(strTagHeader,"\\sa") ;
bNoSpace = TRUE ;
break;
case spacebefore: // sets amount of vertical spacing before paragraph*
strcpy(strTagHeader,"\\sb") ;
bNoSpace = TRUE ;
break;
case spacebetween: // sets amount of vert. spacing betw. lines of para.*
strcpy(strTagHeader,"\\sl") ;
bNoSpace = TRUE ;
break;
case requiredlinebreak: // breaks current line without ending paragraph*
strcpy(strTagHeader,"\\line") ;
bNoSpace = TRUE ;
break;
case tab: // inserts a tab character*
strcpy(strTagHeader,"\\tab") ;
bNoSpace = TRUE ;
break;
case defformat:
strcpy(strTagHeader,"\\defformat") ;
bNoSpace = TRUE ;
break;
case firstlineindent: // sets first-line indent for paragraph*
strcpy(strTagHeader,"\\fi") ;
bNoSpace = TRUE ;
break ;
case leftindent: // sets left indent for the paragraph*
strcpy(strTagHeader,"\\li") ;
bNoSpace = TRUE ;
break;
case rightindent: // sets the right indent for the paragraph*
strcpy(strTagHeader,"\\ri") ;
bNoSpace = TRUE ;
break;
case bitmapcharacter: // displays specified bitmap or metafile in
// current line of text*
strcpy(strTagHeader,"\\{bmc") ; // note that this is NOT an RTF tag!
strcpy(strTagTrailer, "\\}") ;
bNoSpace = FALSE ;
break;
case box: // draws a box around the current paragraph/pict.*
strcpy(strTagHeader,"\\box") ;
bNoSpace = TRUE ;
break;
case foregroundcolor: // sets foreground color*
strcpy(strTagHeader,"\\cf") ; // note that this requires colortable support
break;
case pard: // restores para. properties to default values*
strcpy(strTagHeader,"\\pard") ;
break;
case plain: // restores character properties to default values*
strcpy(strTagHeader,"\\plain") ;
break;
case italic: // starts italic text*
strcpy(strTagHeader,"{\\i") ;
strcpy(strTagTrailer, "}") ;
break;
case smallcaps: // starts small-capital text*
strcpy(strTagHeader,"{\\scaps") ;
strcpy(strTagTrailer, "}") ;
break;
case spacechar:
strcpy(strTagHeader,"") ;
strcpy(strTagTrailer, "") ;
hardspace = *ptrTokenNext ; // set hardspace (non-stripable initial whitespace)
if ('\n' == hardspace)
hardspace == '%' ; // reset hardspace character to default
return RC_OK ; // generate no output file text for this tag
break;
case keepnext: // creates non-scrolling rgn at top of help window*
strcpy(strTagHeader,"\\keepn") ;
bNoSpace = TRUE ;
break; // prevents WinHelp from wrapping text to fit help wnd*
case keep:
strcpy(strTagHeader,"\\keep") ;
bNoSpace = TRUE ;
break;
default: // this is 'plaintext' type...
*(ptrStartOfLine+lenCmd) = ' ' ; // put the space we removed back..
bNoSpace = TRUE ;
ptrTokenNext = &pLine[0] ; // and prepare to write the entire string out...
}
// now write the generated text...
if ( strHasCRLF = strstr( ptrTokenNext, "\n" ) )
*strHasCRLF = '\0' ; // remove newline
// note that hardspace chars must be the first character(s) of a command arg
if ( hardspace == *ptrTokenNext )
{
ptrTmp = ptrTokenNext ; // don't modify ptrTokenNext
while( hardspace == *ptrTmp ) // convert hardspace characters to spaces
{
*ptrTmp = ' ' ;
ptrTmp++ ;
}
}
// certain commands, like /fs CANNOT have a space between it and its numeric arg
if (TRUE == bNoSpace)
rc = fprintf(flOutput,"%s%s%s\n",strTagHeader,ptrTokenNext,strTagTrailer) ;
else
rc = fprintf(flOutput,"%s %s%s\n",strTagHeader,ptrTokenNext,strTagTrailer) ;
if (rc < 0)
{
printf("RTFHELP: error from fprintf\n") ;
exit(LIBRARY_ERROR) ;
}
return RC_OK ;
}
// *Microsoft Corporation. Programmer's Reference, Volume 4: Resources.
// (Redmond, Washington: Microsoft Corporation, 1992), Chapter 15.